function Run-Threaded
{
	[CmdletBinding()] 
	param(
		[Parameter(ValueFromPipeline=$true)]
		$Task,
		[Parameter(Mandatory=$true)]
		[string]$Description,
		[int]$Threads=(Get-LogicalProcessorCount))
		
	begin{
		$Tasks = @()
		$Jobs = @()
		$StartTime = Get-Date
		if($Threads -eq $null -or $Threads -eq 0)
		{
		  Write-Error "Invalid threads argument is null or 0: $Threads"
		}
	}
	process{	
		$Tasks += $Task
	}
	
	
	end{
		$AllJobs = @()
		$NumberOfTasks = $Tasks.length
		while($Tasks.length -gt 0 -or $Jobs.length -gt 0){		
			while($Tasks.length -gt 0 -and $Jobs.length -lt $Threads)
			{		
				$Task, $Tasks = $Tasks
				$Tasks = @($Tasks | where { $_ -ne $null } )
				
				if($Threads -gt 1 -and $NumberOfTasks -gt 1){
					Write-Host -ForegroundColor Cyan "Starting background task: $($Task.Description)"
				
					$Job = Start-Job -ArgumentList $Task.ArgumentList -ScriptBlock $Task.ScriptBlock
					$AllJobs += $Job
					$Jobs += $Job
				}else{
					Write-Host -ForegroundColor Cyan "$($Task.Description)"					
					Invoke-Command -ScriptBlock $Task.ScriptBlock -ArgumentList $Task.ArgumentList
				}
			}	
		 	$Jobs | foreach { 
					$_ | Wait-Job -Timeout 1 | Receive-Job
				}
			$Job$s = @($Jobs | Where-Object { $_.State -eq 'Running' -or $_.HasMoreData })			
		}
		$AllJobs | Remove-Job		
		Write-Host -ForegroundColor Yellow $Description completed in ((Get-Date) - $StartTime).TotalSeconds seconds
		Write-Host
	}
}

function Get-LogicalProcessorCount
{
	Get-WmiObject win32_computersystem | foreach { $_.NumberOfLogicalProcessors }
}